#pragma once
#include <queue>
#include <pthread.h>
#include <iostream>

using namespace std;

namespace threadpool
{
    const int g_num = 5;

    template <class T>
    class ThreadPool
    {
    private:
        ThreadPool<T>(const int &num = g_num) : _num(num)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);
        }
        ~ThreadPool<T>()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }

        ThreadPool<T>(const ThreadPool<T> &tp) = delete;
        ThreadPool<T> &operator=(const ThreadPool<T> &tp) = delete;
        void Wait()
        {
            pthread_cond_wait(&_cond, &_mutex);
        }

        void Lock()
        {
            pthread_mutex_lock(&_mutex);
        }

        void Unlock()
        {
            pthread_mutex_unlock(&_mutex);
        }

    public:
        void Pop(T *out)
        {

            *out = _task_queue.front();
            _task_queue.pop();
        }

        void Push(const T &data)
        {
            Lock();
            _task_queue.push(data);
            Unlock();
            Wakeup();
        }
        void Wakeup()
        {
            pthread_cond_signal(&_cond);
        }
        static ThreadPool<T> *GetDistance()
        {
            static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
            pthread_mutex_lock(&lock);
            if (_tp == nullptr)
            {
                _tp = new ThreadPool<T>();
            }
            pthread_mutex_unlock(&lock);
            return _tp;
        }
        static void *Rountine(void *args)
        {
            // 线程分离，分线程退出时不用主线程去等待。
            pthread_detach(pthread_self());
            ThreadPool<T> *tp = (ThreadPool<T> *)args;

            while (true)
            {
                tp->Lock();
                // 分线程去处理任务
                while (tp->_task_queue.empty())
                {
                    tp->Wait();
                }
                T t;
                tp->Pop(&t);
                tp->Unlock();
                std::cout << pthread_self() << "得到的数据为 " << t << std::endl;
            }
        }

        void InitThreadPool()
        {
            pthread_t tid;
            for (int i = 0; i < g_num; i++)
            {
                pthread_create(&tid, nullptr, Rountine, (void *)this);
            }
        }

    private:
        // 存放任务的队列
        queue<T> _task_queue;
        // 表示线程池中线程的数目
        int _num;
        static ThreadPool<T> *_tp;
        pthread_mutex_t _mutex;
        pthread_cond_t _cond;
    };
    template <class T>
    ThreadPool<T> *ThreadPool<T>::_tp = nullptr;
}
